﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Walson.Windows.Forms
{
    public partial class PFD : Control
    {
        #region 属性

        private float _Roll;
        /// <summary>
        /// 侧倾角度
        /// </summary>
        public double Roll
        {
            get
            {
                return _Roll;
            }
            set
            {
                while (value < 0)
                    value += 360;
                _Roll = (float)value % 360;
                this.Invalidate();
            }
        }

        private float _Pitch;
        /// <summary>
        /// 俯仰角度
        /// </summary>
        public double Pitch
        {
            get
            {
                return _Pitch;
            }
            set
            {
                while (value < -360)
                    value += 360;
                while (value > 360)
                    value -= 360;
                _Pitch = (float)value % 360;
                this.Invalidate();
            }
        }

        private float _Altitude;
        /// <summary>
        /// 海拔高度
        /// </summary>
        public double Altitude
        {
            get
            {
                return _Altitude;
            }
            set
            {
                _Altitude = (float)value;
                this.Invalidate();
            }
        }

        private float _AirSpeed;
        /// <summary>
        /// 空速
        /// </summary>
        public double AirSpeed
        {
            get
            {
                return _AirSpeed;
            }
            set
            {
                _AirSpeed = (float)value;
                this.Invalidate();
            }
        }

        private float _GroundSpeed;
        /// <summary>
        /// 地速
        /// </summary>
        public double GroundSpeed
        {
            get
            {
                return _GroundSpeed;
            }
            set
            {
                _GroundSpeed = (float)value;
                this.Invalidate();
            }
        }

        private float _BankLimit=45.0f;
        /// <summary>
        /// 侧倾角限制
        /// </summary>
        public double BankLimit
        {
            get
            {
                return _BankLimit;
            }
            set
            {
                while (value > 360)
                    value -= 360;
                while (value < 0)
                    value += 360;

                if (BankLimit != value)
                {
                    _BankLimit = (float)value % 360;
                    this.Invalidate();
                }

            }
        }

        private bool _OverSpeed;
        /// <summary>
        /// 是否超速
        /// </summary>
        public bool OverSpeed
        {
            get
            {
                return _OverSpeed;
            }
            set
            {
                if (value != _OverSpeed)
                {
                    _OverSpeed = value;
                    this.Invalidate();
                }
            }
        }

        private bool _Stall;
        /// <summary>
        /// 是否失速
        /// </summary>
        public bool Stall
        {
            get
            {
                return _Stall;
            }
            set
            {
                if (value != _Stall)
                {
                    _Stall = value;
                    this.Invalidate();
                }
            }
        }

        private float _RelativeAltitude;
        /// <summary>
        /// 相对高度
        /// </summary>
        public double RelativeAltitude
        {
            get
            {
                return _RelativeAltitude;
            }
            set
            {
                _RelativeAltitude = (float)value;
                this.Invalidate();
            }
        }        

        private float _DesiredRelativeAltitude;
        /// <summary>
        /// 预设的海拔高度
        /// </summary>
        public float DesiredRelativeAltitude
        {
            get
            {
                return _DesiredRelativeAltitude;
            }
            set
            {
                _DesiredRelativeAltitude = value;
                this.Invalidate();
            }
        }

        private float _DesiredAirSpeed;
        /// <summary>
        /// 预设的空速
        /// </summary>
        public float DesiredAirSpeed
        {
            get
            {
                return _DesiredAirSpeed;
            }
            set
            {
                _DesiredAirSpeed = value;
                this.Invalidate();
            }
        }

        private float _GroundAltitude;
        /// <summary>
        /// 地面海拔高度
        /// </summary>
        public float GroundAltitude
        {
            get
            {
                return _GroundAltitude;
            }
            set
            {
                _GroundAltitude = value;
                this.Invalidate();
            }
        }

        private bool _UseRelativeAltitude = true;
        public bool UseRelativeAltitude
        {
            get => _UseRelativeAltitude;
            set
            {
                _UseRelativeAltitude = value;
                this.Invalidate();
            }
        }

        private float _Heading;
        /// <summary>
        /// 航向
        /// </summary>
        public float Heading
        {
            get
            {
                return _Heading;
            }
            set
            {
                if (value != _Heading)
                {
                    while (value < 0)
                        value += 360;
                    while (value > 360)
                        value -= 360;
                    _Heading = value;
                    this.Invalidate();
                }
            }
        }

        private float _VerticalSpeed;
        /// <summary>
        /// 垂直速度
        /// </summary>
        public float VerticalSpeed
        {
            get
            {
                return _VerticalSpeed;
            }
            set
            {
                if (_VerticalSpeed != value)
                {
                    _VerticalSpeed = value;
                    this.Invalidate();
                }
            }
        }

        bool _RoundCorner = false;
        /// <summary>
        /// 控件外形为圆角
        /// </summary>
        public bool RoundCorner 
        {
            get=>_RoundCorner;
            set
            {
                _RoundCorner = value;
                this.Invalidate();
            } 
        }


        private Color _PanelColor = Color.FromArgb(57, 49, 66);
        SolidBrush _PanelBrush = new SolidBrush(Color.FromArgb(57, 49, 66));
        /// <summary>
        /// 面板颜色
        /// </summary>
        public Color PanelColor
        {
            get { return _PanelColor; }
            set
            {
                _PanelColor = value;

                if (_PanelBrush != null)
                    _PanelBrush.Dispose();
                _PanelBrush = new SolidBrush(PanelColor);

                this.Invalidate();
            }
        }

        private Color _DarkPanelColor = Color.FromArgb(57, 49, 66);
        SolidBrush _DarkPanelBrush = new SolidBrush(Color.FromArgb(16, 16, 49));
        public Color DarkPanelColor
        {
            get { return _DarkPanelColor; }
            set
            {
                _DarkPanelColor = value;

                if (_DarkPanelBrush != null)
                    _DarkPanelBrush.Dispose();
                _DarkPanelBrush = new SolidBrush(BackColor);
                this.Invalidate();
            }
        }

        private Color _EarthColor = Color.FromArgb(99, 57, 24);
        private SolidBrush _EarthBrush = new SolidBrush(Color.FromArgb(99, 57, 24));
        public Color EarthColor
        {
            get => _EarthColor;
            set
            {
                _EarthColor = value;
                _EarthBrush.Dispose();
                _EarthBrush = new SolidBrush(_EarthColor);
                this.Invalidate();
            }
        }

        private Color _SkyColor = Color.FromArgb(41, 156, 239);
        private SolidBrush _SkyBrush = new SolidBrush(Color.FromArgb(41, 156, 239));
        public Color SkyColor
        {
            get => _SkyColor;
            set
            {
                _SkyColor = value;
                _SkyBrush.Dispose();
                _SkyBrush = new SolidBrush(_SkyColor);
                this.Invalidate();
            }
        }

        private int _LineWidth = 2;
        public int LineWidth
        {
            get => _LineWidth;
            set
            {
                if(value!=_LineWidth)
                {
                    _LineWidth = value;
                    _LinePen = new Pen(ForeColor, value);
                }
            }
        }

        private Color _ForeColor = Color.White;
        public override Color ForeColor
        {
            get => _ForeColor;
            set
            {
                if (_ForeColor != value)
                {
                    _ForeColor = value;
                    _LinePen = new Pen(ForeColor, _LineWidth);
                    _TextBrush = new SolidBrush(this.ForeColor);

                    this.Invalidate();
                }
            }
        }

        private Color _BackColor = Color.FromArgb(16, 16, 49);
        public override Color BackColor
        {
            get => _BackColor;
            set
            {
                _BackColor = value;
                this.Invalidate();
            }
        }

        Font _Font = new Font("微软雅黑", 10, FontStyle.Regular);
        Font _UsedFont,_UsedSmallFont;
        float _FontFactor = 0.85f;
        float _FontSize;
        public override Font Font
        {
            get => _Font;
            set
            {
                _Font = value;
                _FontSize = Math.Min(this.Height, this.Width) / ScaleFactor;
                _UsedFont = new Font(_Font.Name, _FontSize, _Font.Style);
                _UsedSmallFont = new Font(_Font.Name, _FontSize * _FontFactor, _Font.Style);
            }
        }

        private bool _UseAirSpeed = true;
        public bool UseAirSpeed
        {
            get => _UseAirSpeed;
            set
            {
                _UseAirSpeed = value;
                this.Invalidate();
            }
        }

        #endregion

        const float ScaleFactor = 30;
        float 
            _PitchFactor, 
            _AltitudeFactor,
            _SpeedFactor,
            _CompassFactor;

        Pen
            _LinePen,
            _IndicatorPen;

        private SolidBrush _TextBrush;

        //Size
        //    _PitchAndBankSize,
        //    _AltiMeterSize,
        //    _SpeedMeterSize,
        //    _CompassSize,
        //    _VerticalSpeedSize;

        PointF
            _PitchAndBankLocation,
            _AltiMeterLocation,
            _SpeedMeterLocation,
            _CompassLocation,
            _VerticalSpeedLocation;

        Bitmap
             _PitchAndBankBmp,
            _AltiMeterBmp,
            _SpeedMeterBmp,
            _CompassBmp,
            _VerticalSpeedBmp;

        int _BaseLen;


        public PFD()
        {
            InitializeComponent();

            _FontSize = Math.Min(this.Height, this.Width) / ScaleFactor;
            _UsedFont = new Font(_Font.Name, _FontSize, _Font.Style);
            _UsedSmallFont = new Font(_Font.Name, _FontSize * _FontFactor, _Font.Style);

            _LinePen = new Pen(_ForeColor, _LineWidth);
            _TextBrush = new SolidBrush(this.ForeColor);

            _IndicatorPen = new Pen(Color.Magenta, 2);

            PFD_SizeChanged(null, null);

            this.SizeChanged += PFD_SizeChanged;
        }


        private void PFD_SizeChanged(object sender, EventArgs e)
        {
            _BaseLen = Math.Min(this.Width, this.Height);

            // 字体相关参数
            _FontSize = Math.Min(this.Height, this.Width) / ScaleFactor;
            _UsedFont = new Font(_Font.Name, _FontSize, _Font.Style);
            _UsedSmallFont = new Font(_Font.Name, _FontSize * _FontFactor, _Font.Style);

            // 速度相关参数
            _SpeedMeterBmp = new Bitmap((int)(this.Width * 0.15f), (int)(this.Height * 0.9f));
            _SpeedMeterLocation = new PointF(0, this.Height * 0.05f);
            _SpeedFactor = _BaseLen / 15.0f;

            // 水平仪相关参数
            _PitchAndBankBmp =new Bitmap((int)(this.Width * 0.58), (int)(this.Height * 0.75));
            _PitchAndBankLocation = new PointF(this.Width * 0.16f, this.Height * 0.05f);
            _PitchFactor = _BaseLen / 90.0f;

            // 高度计相关参数
            _AltiMeterBmp = new Bitmap((int)(this.Width * 0.15f), (int)(this.Height * 0.9f));
            _AltiMeterLocation = new PointF(this.Width * 0.75f, this.Height * 0.05f);
            _AltitudeFactor = _BaseLen / 15.0f;

            // 垂直速度相关参数
            _VerticalSpeedBmp =new Bitmap((int)(this.Width * 0.11f), (int)(this.Height*0.7));
            _VerticalSpeedLocation=new PointF(this.Width * 0.91f, this.Height * 0.15f);

            // 罗盘相关参数
            _CompassBmp=new Bitmap((int)(this.Width * 0.58), (int)(this.Height * 0.14));
            _CompassLocation = new PointF(this.Width * 0.16f, this.Height * 0.81f);
            _CompassFactor = _BaseLen / 10.0f;

            this.Invalidate();
        }

        private void DrawPitchAndBank()
        {
            int
                width = _PitchAndBankBmp.Width,
                height = _PitchAndBankBmp.Height,
                halfWidth = _PitchAndBankBmp.Width / 2,
                halfHeight = _PitchAndBankBmp.Height / 2;

            using(Graphics g=Graphics.FromImage(_PitchAndBankBmp))
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.InterpolationMode = InterpolationMode.NearestNeighbor;
                g.CompositingMode = CompositingMode.SourceOver;
                g.CompositingQuality = CompositingQuality.HighSpeed;
                g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
                g.TextRenderingHint = TextRenderingHint.SystemDefault;


                Rectangle rect;

                g.Clear(EarthColor);

                // 设置平移
                g.TranslateTransform(halfWidth, halfHeight);

                // 设置旋转
                if (_Roll != 0)
                    g.RotateTransform(0 - _Roll);


                if (_Pitch != 0)
                    g.TranslateTransform(0, _Pitch * _PitchFactor);

                // 绘制天和地
                var polygon = new PointF[4];
                polygon[0] = new PointF(-width * 5f, 0f);
                polygon[1] = new PointF(width * 5f, 0f);
                polygon[2] = new PointF(width * 5f, -height * 5f);
                polygon[3] = new PointF(-width * 5f, -height * 5f);
                //g.FillPolygon(new SolidBrush(Color.FromArgb(41, 156, 239)), polygon);
                g.FillPolygon(_SkyBrush, polygon);
                // 天地分界线
                g.DrawLine(_LinePen, -width * 0.25f, 0, width * 0.25f, 0);

                g.ResetTransform();




                g.TranslateTransform(halfWidth, halfHeight);
                // 中间的小方块
                PointF[] centerIndicator = new PointF[5];
                int squareWidth = (int)(_BaseLen * 0.014f);
                //Rectangle rect = new Rectangle(-squareWidth, 0, squareWidth * 2, squareWidth * 2);
                centerIndicator[0] = new PointF(squareWidth, 0);
                centerIndicator[1] = new PointF(squareWidth, squareWidth * 2);
                centerIndicator[2] = new PointF(-squareWidth, squareWidth * 2);
                centerIndicator[3] = new PointF(-squareWidth, 0);
                centerIndicator[4] = new PointF(squareWidth, 0);
                g.FillPolygon(Brushes.Black, centerIndicator);
                g.DrawLines(_LinePen, centerIndicator);

                // 绘制水平指示
                float centerIndicatorWidth = _BaseLen * 0.1f;
                float centerIndicatorGap = _BaseLen * 0.2f;
                float barWidth = _BaseLen * 0.015f;
                float centerIndicatorHeight = _BaseLen * 0.05f;
                centerIndicator = new PointF[7];
                centerIndicator[0] = new PointF(-centerIndicatorGap, 0);
                centerIndicator[1] = new PointF(-centerIndicatorWidth - centerIndicatorGap, 0);
                centerIndicator[2] = new PointF(-centerIndicatorWidth - centerIndicatorGap, barWidth);
                centerIndicator[3] = new PointF(-centerIndicatorGap - barWidth, barWidth);
                centerIndicator[4] = new PointF(-centerIndicatorGap - barWidth, centerIndicatorHeight);
                centerIndicator[5] = new PointF(-centerIndicatorGap, centerIndicatorHeight);
                centerIndicator[6] = new PointF(-centerIndicatorGap, 0);
                g.FillPolygon(Brushes.Black, centerIndicator);
                g.DrawLines(_LinePen, centerIndicator);

                centerIndicator[0] = new PointF(centerIndicatorGap, 0);
                centerIndicator[1] = new PointF(centerIndicatorWidth + centerIndicatorGap, 0);
                centerIndicator[2] = new PointF(centerIndicatorWidth + centerIndicatorGap, barWidth);
                centerIndicator[3] = new PointF(centerIndicatorGap + barWidth, barWidth);
                centerIndicator[4] = new PointF(centerIndicatorGap + barWidth, centerIndicatorHeight);
                centerIndicator[5] = new PointF(centerIndicatorGap, centerIndicatorHeight);
                centerIndicator[6] = new PointF(centerIndicatorGap, 0);
                g.FillPolygon(Brushes.Black, centerIndicator);
                g.DrawLines(_LinePen, centerIndicator);
                g.ResetTransform();




                // 设置平移
                g.TranslateTransform(halfWidth, halfHeight);

                // 设置旋转
                if (_Roll != 0)
                    g.RotateTransform(0 - _Roll);


                if (_Pitch != 0)
                    g.TranslateTransform(0, _Pitch * _PitchFactor);


                float topPosY = -_Pitch * _PitchFactor - halfHeight;
                float bottomPosY = halfHeight - _Pitch * _PitchFactor;
                float topOffset = topPosY + height * 0.25f;          // 0.25是俯仰刻度距离顶端的百分比
                float bottomOffset = bottomPosY - height * 0.1f;    // 0.1是俯仰刻度距离底端的百分比

                // 坡度刻度
                bool b;
                float startPos = 0, endPos;
                float y;
                for (int i = 180; i >= -180; i -= 5)
                {                    
                    y = 0 - i * _PitchFactor;

                    if (y < topOffset || y>bottomOffset)
                        continue;

                    string str = i.ToString();
                    SizeF txtSize = g.MeasureString(str, _UsedSmallFont);
                    b = i % 10 == 0;
                    if (b)
                    {
                        startPos = -halfWidth * 0.25f;
                    }
                    else
                    {
                        startPos = -halfWidth * 0.125f;
                    }

                    endPos = 0 - startPos;
                    g.DrawLine(_LinePen, startPos, y, endPos, y);
                    if (b)
                    {
                        StringFormat format = StringFormat.GenericTypographic;
                        var rectLeft = new RectangleF(startPos - txtSize.Width - 5, y - txtSize.Height / 2, txtSize.Width, txtSize.Height);
                        var rectRight = new RectangleF(endPos + 5, y - txtSize.Height / 2, txtSize.Width, txtSize.Height);
                        float size = g.DpiY * _UsedSmallFont.SizeInPoints / 72; ;
                        GraphicsPath path = new GraphicsPath();
                        path.AddString(str, _UsedSmallFont.FontFamily, (int)_UsedSmallFont.Style, size, rectLeft, format);
                        path.AddString(str, _UsedSmallFont.FontFamily, (int)_UsedSmallFont.Style, size, rectRight, format);
                        g.DrawPath(new Pen(Color.Black, 2), path);
                        g.FillPath(Brushes.White, path);
                        //g.DrawString(str, _UsedFont, _TextBrush, startPos - txtSize.Width - 5, y - txtSize.Height / 2);
                    }
                }

                
                // 绘制顶上的坡度指示器
                double r1 = _BaseLen * 0.3, r2 = r1 * 0.94, r3 = r1 * 1.2;

                rect = new Rectangle((int)-r2, (int)(-r2), (int)r2 * 2, (int)r2 * 2);
                g.DrawArc(_LinePen, rect, -160, 140);

                g.RotateTransform(110);
                for (int i = -7; i <= 7; i++)
                {
                    g.DrawLine(_LinePen, 0, (float)r1, 0, (float)r2);

                    string str = Math.Abs(i * 10).ToString();
                    SizeF txtSize = g.MeasureString(str, _UsedSmallFont);

                    //g.DrawString(str, _UsedFont, _TextBrush, -txtSize.Width / 2, (float)(-r3));

                    if (i % 2 != 0)
                    {
                        g.RotateTransform(180);
                        StringFormat format = StringFormat.GenericTypographic;
                        var rectf = new RectangleF(-txtSize.Width / 2 + 5, (float)(-r3), txtSize.Width, txtSize.Height);
                        float size = g.DpiY * _UsedSmallFont.SizeInPoints / 72; ;
                        GraphicsPath path = new GraphicsPath();
                        path.AddString(str, _UsedSmallFont.FontFamily, (int)_UsedSmallFont.Style, size, rectf, format);
                        g.DrawPath(new Pen(Color.Black, 2), path);
                        g.FillPath(Brushes.White, path);
                        g.RotateTransform(190);
                    }
                    else
                        g.RotateTransform(10);
                    
                }
                g.ResetTransform();


                if (_Roll>=-70 && _Roll<=70)
                {
                    g.TranslateTransform(halfWidth, halfHeight);
                    // 绘制坡度的指示三角
                    PointF[] triangle = new PointF[4];
                    float triangleWidth = _BaseLen * 0.030f;
                    float triangleHalfWidth = triangleWidth / 2;
                    float triangleHeight = (float)(triangleHalfWidth * Math.Tan(Math.PI / 3));
                    float triangleOffset =  (float)-r2+5;//topPosY + height * 0.13f;

                    triangle[0] = new PointF(0, triangleOffset);
                    triangle[1] = new PointF(-triangleHalfWidth, triangleOffset + triangleHeight);
                    triangle[2] = new PointF(triangleHalfWidth, triangleOffset + triangleHeight);
                    triangle[3] = new PointF(0, triangleOffset);
                    g.DrawLines(_LinePen, triangle);
                    if (_Roll < _BankLimit || _Roll > 360 - _BankLimit)
                        g.FillPolygon(Brushes.Yellow, triangle);
                    else
                        g.FillPolygon(Brushes.Red, triangle);
                    g.ResetTransform();
                }


                g.ResetTransform();

                // 绘制圆角
                rect = new Rectangle(0, 0, width, height);
                int radius = _BaseLen/5;
                GraphicsPath roundRect = new System.Drawing.Drawing2D.GraphicsPath();
                //顶端 
                roundRect.AddLine(rect.Left + radius - 1, rect.Top - 1, rect.Right - radius, rect.Top - 1);
                //右上角 
                roundRect.AddArc(rect.Right - radius, rect.Top - 1, radius, radius, 270, 90);
                //右边 
                roundRect.AddLine(rect.Right, rect.Top + radius, rect.Right, rect.Bottom - radius);
                //右下角
                roundRect.AddArc(rect.Right - radius, rect.Bottom - radius, radius, radius, 0, 90);
                //底边 
                roundRect.AddLine(rect.Right - radius, rect.Bottom, rect.Left + radius, rect.Bottom);
                //左下角 
                roundRect.AddArc(rect.Left - 1, rect.Bottom - radius, radius, radius, 90, 90);
                //左边 
                roundRect.AddLine(rect.Left - 1, rect.Top + radius, rect.Left - 1, rect.Bottom - radius);
                //左上角 
                roundRect.AddArc(rect.Left - 1, rect.Top - 1, radius, radius, 180, 90);
                // 外框
                roundRect.AddRectangle(rect);
                g.FillRegion(new SolidBrush(this.BackColor), new Region(roundRect));
            }
        }

        private void DrawAltitude()
        {
            int
                width = _AltiMeterBmp.Width,
                height = _AltiMeterBmp.Height,
                halfWidth = _AltiMeterBmp.Width / 2,
                halfHeight = _AltiMeterBmp.Height / 2;

            double alt;
            if (UseRelativeAltitude)
                alt = RelativeAltitude;
            else
                alt = GroundAltitude + RelativeAltitude;

            using (Graphics g = Graphics.FromImage(_AltiMeterBmp))
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.InterpolationMode = InterpolationMode.NearestNeighbor;
                g.CompositingMode = CompositingMode.SourceOver;
                g.CompositingQuality = CompositingQuality.HighSpeed;
                g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
                g.TextRenderingHint = TextRenderingHint.SystemDefault;

                g.Clear(_PanelColor);

                PointF[] line = new PointF[2];
                PointF[] polygon;
                string str;

                g.TranslateTransform(0, halfHeight+ _RelativeAltitude * _AltitudeFactor / 10);

                int centerY = (int)(-alt / 10 * _AltitudeFactor);
                int topY = centerY - halfHeight;
                int bottomY = centerY + halfHeight;

                int start =(int)alt / 10-10;
                int end = start + 20;
                SizeF strSize = g.MeasureString("123", _UsedSmallFont);
                for (int i =start; i < end; i++)
                {
                    line[0] = new PointF(0, -i * _AltitudeFactor);
                    line[1] = new PointF(_BaseLen * 0.03f, -i * _AltitudeFactor);
                    g.DrawLine(_LinePen, line[0], line[1]);

                    if (i % 2 == 0)
                    {
                        str = (i * 10).ToString("D3");
                        g.DrawString(str, _UsedSmallFont, _TextBrush, _BaseLen * 0.04f, -i * _AltitudeFactor - strSize.Height / 2);
                    }
                }

                // 绘制设置高度
                float basePointY;
                float indicatorHeight = _BaseLen * 0.02f;
                float indicatorWidth = _BaseLen * 0.1f;
                basePointY = -DesiredRelativeAltitude / 10.0f * _AltitudeFactor;
                strSize = g.MeasureString("123", _UsedFont);
                polygon = new PointF[6];

                if (basePointY < topY)
                    basePointY = topY;
                else if (basePointY > bottomY)
                    basePointY = bottomY;
                polygon[0] = new PointF(_BaseLen * 0.03f + 3, basePointY);
                polygon[1] = new PointF(_BaseLen * 0.07f + 3, basePointY - indicatorHeight);
                polygon[2] = new PointF(_BaseLen * 0.07f + 3 + indicatorWidth, basePointY - indicatorHeight);
                polygon[3] = new PointF(_BaseLen * 0.07f + 3 + indicatorWidth, basePointY + indicatorHeight);
                polygon[4] = new PointF(_BaseLen * 0.07f + 3, basePointY + indicatorHeight);
                polygon[5] = new PointF(_BaseLen * 0.03f + 3, basePointY);

                g.DrawLines(_IndicatorPen, polygon);

                g.ResetTransform();
                g.TranslateTransform(0, halfHeight);
                // 绘制高度读数
                //fontHeight = (strSize.Height + 10) / 2f;
                indicatorHeight = _BaseLen * 0.04f;
                indicatorWidth = _BaseLen * 0.15f;
                basePointY = 0;
                polygon = new PointF[8];
                polygon[0] = new PointF(_BaseLen * 0.03f + 3, 0);
                polygon[1] = new PointF(_BaseLen * 0.05f + 3, basePointY - indicatorHeight / 3);
                polygon[2] = new PointF(_BaseLen * 0.05f + 3, basePointY - indicatorHeight);
                polygon[3] = new PointF(_BaseLen * 0.05f + 3 + indicatorWidth, basePointY - indicatorHeight);
                polygon[4] = new PointF(_BaseLen * 0.05f + 3 + indicatorWidth, basePointY + indicatorHeight);
                polygon[5] = new PointF(_BaseLen * 0.05f + 3, basePointY + indicatorHeight);
                polygon[6] = new PointF(_BaseLen * 0.05f + 3, basePointY + indicatorHeight / 3);
                polygon[7] = new PointF(_BaseLen * 0.03f + 3, 0);
                g.FillPolygon(_DarkPanelBrush, polygon);
                g.DrawLines(_LinePen, polygon);
                g.DrawString(((int)alt).ToString("D3"), _UsedFont, _TextBrush, _BaseLen * 0.05f + 3 + indicatorWidth/2- strSize.Width/2, basePointY - strSize.Height / 2.0f);

                g.ResetTransform();

                if (UseRelativeAltitude)
                {
                    strSize = g.MeasureString("RLT", _UsedSmallFont);
                    g.DrawString("RLT\r\n  m", _UsedSmallFont, _TextBrush, width-strSize.Width, 0);
                }
                else
                {
                    strSize = g.MeasureString("MSL", _UsedSmallFont);
                    g.DrawString("MSL\r\n  m", _UsedSmallFont, _TextBrush, width - strSize.Width, 0);
                }
            }
        }

        private void DrawSpeed()
        {
            int
               width = _SpeedMeterBmp.Width,
               height = _SpeedMeterBmp.Height,
               halfWidth = _SpeedMeterBmp.Width / 2,
               halfHeight = _SpeedMeterBmp.Height / 2;

            float speed;
            if (UseAirSpeed)
                speed =(float) AirSpeed;
            else
                speed = (float)GroundSpeed;

            using (Graphics g = Graphics.FromImage(_SpeedMeterBmp))
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.InterpolationMode = InterpolationMode.NearestNeighbor;
                g.CompositingMode = CompositingMode.SourceOver;
                g.CompositingQuality = CompositingQuality.HighSpeed;
                g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
                g.TextRenderingHint = TextRenderingHint.SystemDefault;

                g.Clear(_PanelColor);

                PointF[] line = new PointF[2];
                PointF[] polygon;
                string str;

                g.TranslateTransform(0, halfHeight + speed * _SpeedFactor );

                int centerY = (int)(-speed * _SpeedFactor);
                int topY = centerY - halfHeight;
                int bottomY = centerY + halfHeight;

                int start = (int)speed - 10;
                int end = start + 20;
                SizeF strSize = g.MeasureString("123", _UsedSmallFont);
                for (int i = start; i < end; i++)
                {
                    line[0] = new PointF(width - _BaseLen *0.03f, -i * _SpeedFactor);
                    line[1] = new PointF(_BaseLen, -i * _SpeedFactor);
                    g.DrawLine(_LinePen, line[0], line[1]);

                    if (i % 2 == 0)
                    {
                        str = (i).ToString("D3");
                        g.DrawString(str, _UsedSmallFont, _TextBrush, width - _BaseLen * 0.04f - strSize.Width, -i * _SpeedFactor - strSize.Height / 2);
                    }
                }

                // 绘制设置速度
                float basePointY;
                float indicatorHeight = _BaseLen * 0.02f;
                float indicatorWidth = _BaseLen * 0.1f;
                basePointY = -DesiredAirSpeed * _SpeedFactor;

                polygon = new PointF[6];

                if (basePointY < topY)
                    basePointY = topY;
                else if (basePointY > bottomY)
                    basePointY = bottomY;
                polygon[0] = new PointF(width - (_BaseLen * 0.03f + 3), basePointY);
                polygon[1] = new PointF(width - (_BaseLen * 0.07f + 3), basePointY - indicatorHeight);
                polygon[2] = new PointF(width - (_BaseLen * 0.07f + 3 + indicatorWidth), basePointY - indicatorHeight);
                polygon[3] = new PointF(width - (_BaseLen * 0.07f + 3 + indicatorWidth), basePointY + indicatorHeight);
                polygon[4] = new PointF(width - (_BaseLen * 0.07f + 3), basePointY + indicatorHeight);
                polygon[5] = new PointF(width - (_BaseLen * 0.03f + 3), basePointY);

                g.DrawLines(_IndicatorPen, polygon);

                g.ResetTransform();
                g.TranslateTransform(0, halfHeight);
                strSize = g.MeasureString("123", _UsedFont);
                // 绘制速度读数
                indicatorHeight = _BaseLen * 0.04f;
                indicatorWidth = _BaseLen * 0.15f;
                basePointY = 0;
                polygon = new PointF[8];
                polygon[0] = new PointF(width - (_BaseLen * 0.03f + 3), 0);
                polygon[1] = new PointF(width - (_BaseLen * 0.05f + 3), basePointY - indicatorHeight / 3);
                polygon[2] = new PointF(width - (_BaseLen * 0.05f + 3), basePointY - indicatorHeight);
                polygon[3] = new PointF(width - (_BaseLen * 0.05f + 3 + strSize.Width*1.5f), basePointY - indicatorHeight);
                //polygon[3] = new PointF(_BaseLen * 0.01f, basePointY - indicatorHeight);
                polygon[4] = new PointF(width - (_BaseLen * 0.05f + 3 + strSize.Width*1.5f), basePointY + indicatorHeight);
                //polygon[4] = new PointF(_BaseLen * 0.01f , basePointY + indicatorHeight);
                polygon[5] = new PointF(width - (_BaseLen * 0.05f + 3), basePointY + indicatorHeight);
                polygon[6] = new PointF(width - (_BaseLen * 0.05f + 3), basePointY + indicatorHeight / 3);
                polygon[7] = new PointF(width - (_BaseLen * 0.03f + 3), 0);
                g.FillPolygon(_DarkPanelBrush, polygon);
                g.DrawLines(_LinePen, polygon); 
                g.DrawString($"{((int)speed).ToString("D3")}", _UsedFont, _TextBrush, width - (_BaseLen * 0.05f + 3 + indicatorWidth / 2) - strSize.Width / 2,  - (int)(strSize.Height / 2.0f));

                g.ResetTransform();

                if (UseAirSpeed)
                    g.DrawString("AS\r\nm/s", _UsedSmallFont, _TextBrush, 0, 0);
                else
                    g.DrawString("GS\r\nm/s", _UsedSmallFont, _TextBrush, 0, 0);
            }
        }

        private void DrawVerticalSpeed()
        {
            int
               width = _VerticalSpeedBmp.Width,
               height = _VerticalSpeedBmp.Height,
               halfWidth = _VerticalSpeedBmp.Width / 2,
               halfHeight = _VerticalSpeedBmp.Height / 2;

            using (Graphics g = Graphics.FromImage(_VerticalSpeedBmp))
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.InterpolationMode = InterpolationMode.NearestNeighbor;
                g.CompositingMode = CompositingMode.SourceOver;
                g.CompositingQuality = CompositingQuality.HighSpeed;
                g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
                g.TextRenderingHint = TextRenderingHint.SystemDefault;

                float indicatorWidth = width * 0.7f;
                float indicatorWidth2 = width * 0.5f;
                float indicatorHeight2 = height * 0.15f;
                PointF[] polygon = new PointF[7];
                polygon[0] = new PointF(0, 0);
                polygon[1] = new PointF(indicatorWidth2, 0);
                polygon[2] = new PointF(indicatorWidth, height / 2 - indicatorHeight2);
                polygon[3] = new PointF(indicatorWidth, height / 2 + indicatorHeight2);
                polygon[4] = new PointF(indicatorWidth2, height);
                polygon[5] = new PointF(0, height);
                polygon[6] = new PointF(0, 0);
                g.FillPolygon(_PanelBrush, polygon);

                g.TranslateTransform(0, height / 2f);

                PointF[] line = new PointF[2];
                int gap = Math.Max(width, height) / 10 - 2;

                line[0] = new PointF(indicatorWidth, 0);
                if (_VerticalSpeed > 5)
                    line[1] = new PointF(indicatorWidth2, -gap * 5);
                else if (_VerticalSpeed < -5)
                    line[1] = new PointF(indicatorWidth2, -gap * -5);
                else
                    line[1] = new PointF(indicatorWidth2, -gap * _VerticalSpeed);
                g.DrawLine(_LinePen, line[0], line[1]);

                
               
                indicatorWidth = width * 0.3f;
                indicatorWidth2 = width * 0.4f;
                SizeF strSize = g.MeasureString("123", _UsedSmallFont);
                for (int i = 0; i < 6; i++)
                {
                    line[0] = new PointF(indicatorWidth, i * gap);
                    line[1] = new PointF(indicatorWidth2, i * gap);
                    g.DrawLine(_LinePen, line[0], line[1]);

                    line[0] = new PointF(indicatorWidth, -i * gap);
                    line[1] = new PointF(indicatorWidth2, -i * gap);
                    g.DrawLine(_LinePen, line[0], line[1]);

                    g.DrawString(i.ToString(), _UsedSmallFont, _TextBrush, 2, i * gap - strSize.Height / 2);
                    g.DrawString(i.ToString(), _UsedSmallFont, _TextBrush, 2, -i * gap - strSize.Height / 2);
                }

                
            }
        }

        private void DrawCompass()
        {
            int
               width = _CompassBmp.Width,
               height = _CompassBmp.Height,
               halfWidth = _CompassBmp.Width / 2,
               halfHeight = _CompassBmp.Height / 2;

            int _Min = 0, _Max = 360;

            using (Graphics g = Graphics.FromImage(_CompassBmp))
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.InterpolationMode = InterpolationMode.NearestNeighbor;
                g.CompositingMode = CompositingMode.SourceOver;
                g.CompositingQuality = CompositingQuality.HighSpeed;
                g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
                g.TextRenderingHint = TextRenderingHint.SystemDefault;

                g.Clear(_PanelColor);

                PointF[] polygon = new PointF[3];
                float triangleWidth = _BaseLen * 0.015f;
                float triangleHeight = (float)(triangleWidth * Math.Tan(Math.PI / 3));
                polygon[0] = new PointF(width / 2, triangleHeight);
                polygon[1] = new PointF(width / 2 - triangleWidth, 2);
                polygon[2] = new PointF(width / 2 + triangleWidth, 2);

                g.FillPolygon(_TextBrush, polygon);

                float offset = (float)(_Heading - (int)_Heading);
                float start = width / 2 - offset * _CompassFactor;
                PointF[] line = new PointF[2];
                float x;
                for (int i = 0; i < width / (_CompassFactor / 2); i++)
                {
                    x = i * _CompassFactor / 2;
                    line[0] = new PointF(start + i * _CompassFactor / 2, 10);
                    line[1] = new PointF(start + i * _CompassFactor / 2, 17);
                    g.DrawLine(_LinePen, line[0], line[1]);

                    line[0] = new PointF(start - i * _CompassFactor / 2, 10);
                    line[1] = new PointF(start - i * _CompassFactor / 2, 17);
                    g.DrawLine(_LinePen, line[0], line[1]);

                    if (i % 2 == 0)
                    {
                        int h;
                        float len;

                        if (_Heading >= 0)
                            h = (int)Math.Floor(_Heading + i / 2);
                        else
                            h = (int)Math.Ceiling(_Heading + i / 2);


                        while (h < _Min)
                            h = _Max - (_Min - h);
                        while (h > _Max)
                            h = _Min + h - _Max;
                        if (h == _Max)
                            h = _Min;

                        len = g.MeasureString(h.ToString(), _UsedSmallFont).Width;
                        g.DrawString(h.ToString(), _UsedSmallFont, _TextBrush, start + i * _CompassFactor / 2 - len / 2, 19);

                        if (_Heading >= 0)
                            h = (int)Math.Floor(_Heading - i / 2);
                        else
                            h = (int)Math.Ceiling(_Heading - i / 2);

                        while (h < _Min)
                            h = _Max - (_Min - h);
                        while (h > _Max)
                            h = _Min + h - _Max;
                        if (h == _Max)
                            h = _Min;
                        len = g.MeasureString(h.ToString(), _UsedSmallFont).Width;
                        g.DrawString(h.ToString(), _UsedSmallFont, _TextBrush, start - i * _CompassFactor / 2 - len / 2, 19);
                    }
                }

                g.ResetTransform();

            }
        }

















        protected override void OnPaint(PaintEventArgs e)
        {
            using (Bitmap bmp=new Bitmap(this.Width,this.Height))
            {
                using(Graphics g=Graphics.FromImage(bmp))
                {
                    g.Clear(BackColor);

                    DrawPitchAndBank();
                    DrawSpeed();
                    DrawAltitude();
                    DrawVerticalSpeed();
                    DrawCompass();

                    g.DrawImage(_PitchAndBankBmp, _PitchAndBankLocation);
                    g.DrawImage(_AltiMeterBmp, _AltiMeterLocation);
                    g.DrawImage(_SpeedMeterBmp, _SpeedMeterLocation);
                    g.DrawImage(_VerticalSpeedBmp, _VerticalSpeedLocation);
                    g.DrawImage(_CompassBmp, _CompassLocation);

                    
                }
                e.Graphics.DrawImage(bmp, 0, 0);
            }

            if (RoundCorner)
            {
                // 绘制圆角
                Rectangle rect = new Rectangle(0, 0, this.Width, this.Height);
                int radius = _BaseLen / 10;
                System.Drawing.Drawing2D.GraphicsPath roundRect = new System.Drawing.Drawing2D.GraphicsPath();
                //顶端 
                roundRect.AddLine(rect.Left + radius - 1, rect.Top - 1, rect.Right - radius, rect.Top - 1);
                //右上角 
                roundRect.AddArc(rect.Right - radius, rect.Top - 1, radius, radius, 270, 90);
                //右边 
                roundRect.AddLine(rect.Right, rect.Top + radius, rect.Right, rect.Bottom - radius);
                //右下角
                roundRect.AddArc(rect.Right - radius, rect.Bottom - radius, radius, radius, 0, 90);
                //底边 
                roundRect.AddLine(rect.Right - radius, rect.Bottom, rect.Left + radius, rect.Bottom);
                //左下角 
                roundRect.AddArc(rect.Left - 1, rect.Bottom - radius, radius, radius, 90, 90);
                //左边 
                roundRect.AddLine(rect.Left - 1, rect.Top + radius, rect.Left - 1, rect.Bottom - radius);
                //左上角 
                roundRect.AddArc(rect.Left - 1, rect.Top - 1, radius, radius, 180, 90);

                this.Region = new Region(roundRect);
            }

            base.OnPaint(e);
        }
    }
}
